import pygame
import random

# 游戏窗口区域（矩形区域）
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
FRAME_INTERVAL = 10                             # 逐帧动画间隔帧数为10

class GameSprite(pygame.sprite.Sprite):
    """游戏精灵类"""
    res_path = "./res/images/"  # 图片资源路径

    def __init__(self, image_name, speed, *groups):
        """构造方法
        :param image_name： 要加载的图片文件名
        :param speed：移动速度，0 表示静止
        :param groups：要添加到的精灵组，不传值则不添加
        """

        super().__init__(*groups)
        # 图像
        self.image = pygame.image.load(self.res_path + image_name)
        self.rect = self.image.get_rect()  # 矩形区域，默认在左上角
        self.speed = speed  # 移动速度

    def update(self, *args):
        """更新精灵未知，默认在垂直方向移动"""
        self.rect.y += self.speed

class Background(GameSprite):
    """"背景精灵"""

    def __init__(self, is_alt, *groups):
        # 调用父类方法实现精灵的创建
        super().__init__("background.png", 1, *groups)
        # 判断是否有另一个精灵，如果是，需要设置初始位置
        if is_alt:
            self.rect.y = -self.rect.h  # 设置到游戏窗口正上方

    def update(self, *args):
        # 调用父类的方法实现向下运动
        super().update(*args)  # 向下移动
        # 判断是否移除屏幕，如果移除屏幕，将图像设置到屏幕上方
        if self.rect.y >= self.rect.h:
            self.rect.y = -self.rect.h


class StatusButton(GameSprite):
    """状态按钮类"""

    def __init__(self, image_names, *groups):
        """构造方法
        :param image_names:要加载的图像名称列表
        :param groups: 要添加到的精灵组
        """
        super().__init__(image_names[0], 0, *groups)
        # 加载图像
        self.images = [pygame.image.load(self.res_path + name)
                       for name in image_names]

    def switch_status(self, is_pause):
        """切换状态
        :param is_pause: 是否暂停
        """
        self.image = self.images[1 if is_pause else 0]


class Label(pygame.sprite.Sprite):
    """文本标签精灵"""

    font_path = "./res/font/MarkerFelt.ttc"  # 字体文件路径

    def __init__(self, text, size, color, *groups):
        """初始化方法

        :param text: 文本内容
        :param size: 字体大小
        :param color: 字体颜色
        :param groups: 要添加到的精灵组
        """
        super().__init__(*groups)

        self.font = pygame.font.Font(self.font_path, size)
        self.color = color

        self.image = self.font.render(text, True, self.color)
        self.rect = self.image.get_rect()

    def set_text(self, text):
        """设置文本，使用指定的文本重新渲染 image，并且更新 rect

        :param text: 文本内容
        """
        self.image = self.font.render(text, True, self.color)
        self.rect = self.image.get_rect()
class Plane(GameSprite):
    """飞机类"""
    def __init__(self, hp, speed, value, wav_name,
                 normal_names, hurt_name, destroy_names, *groups):
        super().__init__(normal_names[0], 0, *groups)
        # 飞机属性
        self.hp = hp
        self.max_hp = hp
        self.value = value
        self.wav_name = wav_name
        # 图像属性
        # 正常图像列表及索引
        self.normal_images = [pygame.image.load(self.res_path + name)
                              for name in normal_names]
        self.normal_index = 0
        # 受伤图像
        self.hurt_image = pygame.image.load(self.res_path + hurt_name)
        # 被摧毁图像列表及索引
        self.destroy_images = [pygame.image.load(self.res_path + name)
                               for name in destroy_names]
        self.destroy_index = 0
    def reset_plane(self):
        """重置飞机"""
        self.hp = self.max_hp                   # 生命值
        self.normal_index = 0                   # 正常状态图像索引
        self.destroy_index = 0                  # 被摧毁状态图像索引
        self.image = self.normal_images[0]      # 恢复正常图像
    def update(self, *args):
        # 如果第 0 个参数为 False，不需要更新图像，直接返回
        if not args[0]:
            return
        # 判断飞机状态
        if self.hp == self.max_hp:              # 未受伤
            self.image = self.normal_images[self.normal_index]
            count = len(self.normal_images)
            self.normal_index = (self.normal_index + 1) % count
        elif self.hp > 0:                       # 受伤
            self.image = self.hurt_image
        else:                                   # 被摧毁
            # 判断是否显示到最后一张图像，如果是说明飞机完全被摧毁
            if self.destroy_index < len(self.destroy_images):
                self.image = self.destroy_images[self.destroy_index]
                self.destroy_index += 1
            else:
                self.reset_plane()              # 重置飞机
class Enemy(Plane):
    """敌机类"""
    def __init__(self, kind, max_speed, *groups):
        # 记录敌机类型和最大速度
        self.kind = kind
        self.max_speed = max_speed
        # 根据类型调用父类方法传递不同参数
        if kind == 0:
            super().__init__(1, 1, 1000, "enemy1_down.wav",
                             ["enemy1.png"], "enemy1.png",
                             ["enemy1_down%d.png" % i for i in range(1, 5)], *groups)
        elif kind == 1:
            super().__init__(6, 1, 6000, "enemy2_down.wav",
                             ["enemy2.png"], "enemy2_hit.png",
                             ["enemy2_down%d.png" % i for i in range(1, 5)], *groups)
        else:
            super().__init__(15, 1, 15000, "enemy3_down.wav",
                             ["enemy3_n1.png", "enemy3_n2.png"], "enemy3_hit.png",
                             ["enemy3_down%d.png" % i for i in range(1, 7)], *groups)
        # 3. 调用重置飞机方法，设置敌机初始位置和速度
        self.reset_plane()
    def reset_plane(self):
        """重置飞机"""
        super().reset_plane()
        # 设置随机x值
        x = random.randint(0,SCREEN_RECT.w - self.rect.w)
        # 设置随机y值
        y = random.randint(0,SCREEN_RECT.h - self.rect.h) - SCREEN_RECT.h
        self.rect.topleft = (x,y)                       # 作为初始位置
        #设置初始速度
        self.speed = random.randint(1, self.max_speed)
    def update(self, *args):
        """更新图像和位置"""
        # 调用父类方法更新飞机图像 - 注意 args 需要拆包
        super().update(*args)
        # 判断敌机是否被摧毁，否则使用速度更新飞机位置
        if self.hp > 0:
            self.rect.y += self.speed
        # 判断是否飞出屏幕，如果是，重置飞机
        if self.rect.y >= SCREEN_RECT.h:
            self.reset_plane()